#include "include/video_render.h"

namespace codec {
void VideoRender::controlFrameRate(
    std::chrono::high_resolution_clock::time_point start_time, int64_t pts,
    int64_t &previous_pts, AVRational time_base) {
  double frame_delay = av_q2d(time_base) * (pts - previous_pts);
  previous_pts = pts;
  auto target_time = start_time + std::chrono::microseconds(
                                      static_cast<long>(frame_delay * 1e6));
  auto usetime = std::chrono::duration_cast<std::chrono::microseconds>(
                     std::chrono::high_resolution_clock::now() - start_time)
                     .count();
  auto diff = frame_delay * 1e6 - static_cast<double>(usetime);
  if (diff > 1000) {
    std::this_thread::sleep_for(
        std::chrono::microseconds(static_cast<int>(diff)));
  }
}
bool VideoRender::init(ANativeWindow *window, const std::string &vertexCode,
                       const std::string &fragmentCode) {
  native_window_ = window;
  // 2. 初始化EGL
  egl_env_.display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  eglInitialize(egl_env_.display, nullptr, nullptr);

  // 3. 配置EGL
  const EGLint configAttribs[] = {EGL_RENDERABLE_TYPE,
                                  EGL_OPENGL_ES3_BIT,
                                  EGL_SURFACE_TYPE,
                                  EGL_WINDOW_BIT,
                                  EGL_BLUE_SIZE,
                                  8,
                                  EGL_GREEN_SIZE,
                                  8,
                                  EGL_RED_SIZE,
                                  8,
                                  EGL_NONE};
  EGLConfig config;
  EGLint numConfigs;
  eglChooseConfig(egl_env_.display, configAttribs, &config, 1, &numConfigs);

  // 4. 创建EGL上下文
  const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
  egl_env_.context = eglCreateContext(egl_env_.display, config, EGL_NO_CONTEXT,
                                      contextAttribs);
  // 5. 创建EGL窗口表面
  egl_env_.surface =
      eglCreateWindowSurface(egl_env_.display, config, native_window_, nullptr);
  // eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  // 解绑 多线程操作要先解绑当前线程上下文，重新绑定线程上下文才能调用gl方法
  // 6. 绑定上下文到当前线程
  eglMakeCurrent(egl_env_.display, egl_env_.surface, egl_env_.surface,
                 egl_env_.context);
  int width = ANativeWindow_getWidth(native_window_);
  int height = ANativeWindow_getHeight(native_window_);
  // 7. 设置视口
  glViewport(0, 0, width, height);
  paprevao();
  prepareShader(vertexCode, fragmentCode);
  eglMakeCurrent(egl_env_.display, EGL_NO_SURFACE, EGL_NO_SURFACE,
                 EGL_NO_CONTEXT);
  return true;
}

void VideoRender::paprevao() {
  // 顶点位置（屏幕坐标系）
  float positions[] = {
      -1.f, -1.f,  // 0:左下
      1.f,  -1.f,  // 1:右下
      -1.f, 1.f,   // 2:左上
      1.f,  1.f    // 3:右上
  };

  float uvs[] = {
      0.0f, 1.0f,  // 0:左下 → 纹理左下
      1.0f, 1.0f,  // 1:右下 → 纹理右下
      0.0f, 0.0f,  // 2:左上 → 纹理左上
      1.0f, 0.0f   // 3:右上 → 纹理右上
  };

  // 索引数组（两个三角形）
  unsigned int indices[] = {
      0, 1, 2,  // 左下→右下→左上
      1, 3, 2   // 右下→右上→左上
  };

  // 2 VBO创建
  GLuint posVbo;
  glGenBuffers(1, &posVbo);               // 创建
  glBindBuffer(GL_ARRAY_BUFFER, posVbo);  // 绑定
  glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions,
               GL_STATIC_DRAW);  // 灌数据
  GLuint uvVbo;
  glGenBuffers(1, &uvVbo);
  glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
  glBufferData(GL_ARRAY_BUFFER, sizeof(uvs), uvs, GL_STATIC_DRAW);

  // 3 EBO创建
  GLuint ebo;
  glGenBuffers(1, &ebo);                       // 创建
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);  // 绑定
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices,
               GL_STATIC_DRAW);  // 灌数据

  // 4 VAO创建
  glGenVertexArrays(1, &vao_);
  glBindVertexArray(vao_);

  // 5 绑定vbo ebo 加入属性描述信息
  // 5.1 加入位置属性描述信息
  glBindBuffer(GL_ARRAY_BUFFER, posVbo);
  glEnableVertexAttribArray(0);
  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *)0);

  // 5.2 加入uv属性描述数据
  glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
  glEnableVertexAttribArray(1);
  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *)0);
  glEnableVertexAttribArray(1);

  int width = ANativeWindow_getWidth(native_window_);
  int height = ANativeWindow_getHeight(native_window_);

  glGenTextures(3, textures);
  // Y分量纹理 (全分辨率)
  glBindTexture(GL_TEXTURE_2D, textures[0]);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED,
               GL_UNSIGNED_BYTE, NULL);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

  // U分量纹理 (1/4分辨率)
  glBindTexture(GL_TEXTURE_2D, textures[1]);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width / 2, height / 2, 0, GL_RED,
               GL_UNSIGNED_BYTE, NULL);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

  // V分量纹理 (1/4分辨率)
  glBindTexture(GL_TEXTURE_2D, textures[2]);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width / 2, height / 2, 0, GL_RED,
               GL_UNSIGNED_BYTE, NULL);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

  // 5.3 加入ebo到当前的vao
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);

  glBindVertexArray(0);
  GLenum err = glGetError();
  if (err != GL_NO_ERROR) {
    __android_log_print(ANDROID_LOG_ERROR, "render", "paprevao: 0x%x", err);
  }
}

void VideoRender::prepareShader(const std::string &vertexCode,
                                const std::string &fragmentCode) {
  shader = new Shader(vertexCode, fragmentCode);
}

void VideoRender::renderFrame(AVFrame *frame) {
  eglMakeCurrent(egl_env_.display, egl_env_.surface, egl_env_.surface,
                 egl_env_.context);
  glBindTexture(GL_TEXTURE_2D, textures[0]);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, frame->width, frame->height, 0, GL_RED,
               GL_UNSIGNED_BYTE, frame->data[0]);

  // U分量
  glBindTexture(GL_TEXTURE_2D, textures[1]);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, frame->width / 2, frame->height / 2, 0,
               GL_RED, GL_UNSIGNED_BYTE, frame->data[1]);

  // V分量
  glBindTexture(GL_TEXTURE_2D, textures[2]);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, frame->width / 2, frame->height / 2, 0,
               GL_RED, GL_UNSIGNED_BYTE, frame->data[2]);
  GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
  // 绑定当前的program
  shader->begin();
  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, textures[0]);
  glUniform1i(glGetUniformLocation(shader->mProgram, "yTexture"), 0);

  glActiveTexture(GL_TEXTURE1);
  glBindTexture(GL_TEXTURE_2D, textures[1]);
  glUniform1i(glGetUniformLocation(shader->mProgram, "uTexture"), 1);

  glActiveTexture(GL_TEXTURE2);
  glBindTexture(GL_TEXTURE_2D, textures[2]);
  glUniform1i(glGetUniformLocation(shader->mProgram, "vTexture"), 2);
  // 绑定当前的vao
  GL_CALL(glBindVertexArray(vao_));
  // 发出绘制指令
  GL_CALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0));
  GL_CALL(glBindVertexArray(0));
  shader->end();
  eglSwapBuffers(egl_env_.display, egl_env_.surface);
  GLenum err = eglGetError();
  if (err != EGL_SUCCESS) {
    __android_log_print(ANDROID_LOG_ERROR, "render", "renfresh: 0x%x", err);
  }
  GLenum err1 = glGetError();
  if (err1 != GL_NO_ERROR) {
    __android_log_print(ANDROID_LOG_ERROR, "render", "renfresh1: 0x%x", err1);
  }
}
void VideoRender::updateViewPort(int width, int height) {
  glViewport(0, 0, width, height);
}

void VideoRender::release() {
  // 清理资源
  if (egl_env_.display != EGL_NO_DISPLAY) {
    eglMakeCurrent(egl_env_.display, EGL_NO_SURFACE, EGL_NO_SURFACE,
                   EGL_NO_CONTEXT);
    eglDestroySurface(egl_env_.display, egl_env_.surface);
    eglDestroyContext(egl_env_.display, egl_env_.context);
    eglTerminate(egl_env_.display);
  }
  if (native_window_) ANativeWindow_release(native_window_);
  egl_env_.display = EGL_NO_DISPLAY;
  egl_env_.context = EGL_NO_CONTEXT;
  egl_env_.surface = EGL_NO_SURFACE;
  native_window_ = nullptr;
}
}  // namespace codec